package com.tianji.learning.service.impl;

import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.vo.SignResultVO;
import com.tianji.learning.mq.message.SignInMessage;
import com.tianji.learning.service.SignRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;

@Service
@Slf4j
@RequiredArgsConstructor
public class SignRecordServiceImpl implements SignRecordService {

    final StringRedisTemplate redisTemplate;
    final RabbitMqHelper rabbitMqHelper;
    @Override
    public SignResultVO addSignRecords() {
        //1.获取当前登录用户
        Long userId = UserContext.getUser();
        //2.拼接key
        LocalDate now = LocalDate.now();
        int offset = now.getDayOfMonth() - 1;
        String format = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = RedisConstants.SIGN_RECORD_KEY_PREFIX + userId.toString() + format;
        //3.调用bitset方法做签到
        Boolean bit = redisTemplate.opsForValue().setBit(key, offset, true);
        if (bit){
            throw new BizIllegalException("不可重复签到");
        }
        //5.计算连续签到天数
        int countSign = countSignDays(key,now.getDayOfMonth());
        //6.计算是否有连续签到额外积分奖励
        int rewardPoint = 0;//连续签到的额外积分
        switch (countSign){
            case 7: rewardPoint = 10;break;
            case 14: rewardPoint = 20;break;
            case 28: rewardPoint = 40;break;
        }
        //7.保存积分
        rabbitMqHelper.send(
                MqConstants.Exchange.LEARNING_EXCHANGE,
                MqConstants.Key.SIGN_IN,
                SignInMessage.of(userId,rewardPoint+1)
        );
        //8.封装VOa
        SignResultVO signResultVO = new SignResultVO();
        signResultVO.setSignDays(countSign);
        signResultVO.setRewardPoints(rewardPoint);
        return signResultVO;
    }

    @Override
    public Byte[] getSignRecords() {
        //1.获取当前登录用户
        Long userId = UserContext.getUser();
        //2.拼接key
        LocalDate now = LocalDate.now();
        int offset = now.getDayOfMonth() - 1;
        String format = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = RedisConstants.SIGN_RECORD_KEY_PREFIX + userId.toString() + format;
        //3.调用bitfiled命令获取到今天为止总的签到记录
        int dayOfMonth = now.getDayOfMonth();
        List<Long> field = redisTemplate.opsForValue()
                .bitField(key, BitFieldSubCommands.create()
                        .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth))
                        .valueAt(0));
        if (CollUtils.isEmpty(field)){
            return new Byte[0];
        }
        Long num = field.get(0);
        Byte[] ans = new Byte[dayOfMonth];
        while(offset>=0){
            ans[offset--] = (byte)(num & 1);
            num>>=1;
        }
        return ans;
    }


    private int countSignDays(String key, int dayOfMonth) {
        //使用bitfiled 命令
        List<Long> bitField = redisTemplate.opsForValue()
                .bitField(key, BitFieldSubCommands
                        .create()
                        .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth))
                        .valueAt(0));
        if (CollUtils.isEmpty(bitField)){
            return 0;
        }
        Long bit = bitField.get(0);
        int count = 0;
        while((bit & 1)==1){
            count++;
            bit>>=1;
        }
        return count;
    }
}
